//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package board_draw_api_serv

import (
	"context"
	"time"

	"gitcode.com/eteam/api-server/dao"
	"gitcode.com/eteam/api-server/dao/board_dao"
	"gitcode.com/eteam/api-server/notice_serv"
	"gitcode.com/eteam/proto-gen-go.git/board_draw_api"
	"gitcode.com/eteam/proto-gen-go.git/board_draw_type"
	"gitcode.com/eteam/proto-gen-go.git/notices/notices_board"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *BoardDrawApiImpl) CreateEdge(ctx context.Context, req *board_draw_api.CreateEdgeRequest) (*board_draw_api.CreateEdgeResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	drawItem, err := board_dao.DrawInfoDao.Get(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_DRAW,
			ErrMsg: "画稿不存在",
		}, nil
	}
	//检查权限
	memberItem, err := board_dao.MemberInfoDao.Get(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(memberItem.Admin || drawItem.CanEdit(sessItem.UserId)) {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查画稿是否存在
	exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_DRAW,
			ErrMsg: "画稿不存在",
		}, nil
	}

	//检查节点是否存在
	exist, err = board_dao.NodeInfoDao.Exist(ctx, req.BoardId, req.DrawId, req.EdgeKey.FromNodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}
	exist, err = board_dao.NodeInfoDao.Exist(ctx, req.BoardId, req.DrawId, req.EdgeKey.ToNodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_draw_api.CreateEdgeResponse{
			Code:   board_draw_api.CreateEdgeResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}

	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.EdgeInfoDao.Insert(sessCtx, &board_dao.DrawEdgeInfoDbItem{
			BoardId: req.BoardId,
			DrawId:  req.DrawId,
			EdgeKey: board_dao.EdgeKeyDbItem{
				FromNodeId: req.EdgeKey.FromNodeId,
				FromHandle: req.EdgeKey.FromHandle,
				ToNodeId:   req.EdgeKey.ToNodeId,
				ToHandle:   req.EdgeKey.ToHandle,
			},
			BasicInfo: board_dao.BasicEdgeInfoDbItem{
				EdgeType:      req.BasicInfo.EdgeType,
				StrokeWidth:   req.BasicInfo.StrokeWidth,
				Color:         req.BasicInfo.Color,
				HasStartArrow: req.BasicInfo.HasStartArrow,
				HasEndArrow:   req.BasicInfo.HasEndArrow,
				Label:         req.BasicInfo.Label,
				LlmLink:       req.BasicInfo.LlmLink,
			},
			CreateTime: nowTime,
			UpdateTime: nowTime,
		})
		if err != nil {
			return nil, err
		}
		//更新连线数量
		count, err := board_dao.EdgeInfoDao.Count(sessCtx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		err = board_dao.DrawInfoDao.UpdateEdgeCount(sessCtx, req.BoardId, req.DrawId, count, nowTime)
		if err != nil {
			return nil, err
		}
		return &board_draw_api.CreateEdgeResponse{
			Code: board_draw_api.CreateEdgeResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.UpdateDrawNotice{
		BoardId: req.BoardId,
		DrawId:  req.DrawId,
	})
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.CreateEdgeNotice{
		BoardId:    req.BoardId,
		DrawId:     req.DrawId,
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	return ret.(*board_draw_api.CreateEdgeResponse), nil
}

func (apiImpl *BoardDrawApiImpl) UpdateEdgeBasic(ctx context.Context, req *board_draw_api.UpdateEdgeBasicRequest) (*board_draw_api.UpdateEdgeBasicResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	drawItem, err := board_dao.DrawInfoDao.Get(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_NO_DRAW,
			ErrMsg: "画稿不存在",
		}, nil
	}
	//检查权限
	memberItem, err := board_dao.MemberInfoDao.Get(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	edgeItem, err := board_dao.EdgeInfoDao.Get(ctx, req.BoardId, req.DrawId, &board_dao.EdgeKeyDbItem{
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	if err != nil {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_NO_EDGE,
			ErrMsg: "连线不存在",
		}, nil
	}
	if !(memberItem.Admin || drawItem.CanEdit(sessItem.UserId)) {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if edgeItem.BasicInfo.LlmLink {
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code:   board_draw_api.UpdateEdgeBasicResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.EdgeInfoDao.UpdateBaisc(sessCtx, req.BoardId, req.DrawId,
			&board_dao.EdgeKeyDbItem{
				FromNodeId: req.EdgeKey.FromNodeId,
				FromHandle: req.EdgeKey.FromHandle,
				ToNodeId:   req.EdgeKey.ToNodeId,
				ToHandle:   req.EdgeKey.ToHandle,
			},
			&board_dao.BasicEdgeInfoDbItem{
				EdgeType:      req.BasicInfo.EdgeType,
				StrokeWidth:   req.BasicInfo.StrokeWidth,
				Color:         req.BasicInfo.Color,
				HasStartArrow: req.BasicInfo.HasStartArrow,
				HasEndArrow:   req.BasicInfo.HasEndArrow,
				Label:         req.BasicInfo.Label,
				LlmLink:       false, //大模型节点相关边不能被更新
			}, nowTime)
		if err != nil {
			return nil, err
		}
		err = board_dao.DrawInfoDao.SetUpdateTime(sessCtx, req.BoardId, req.DrawId, nowTime)
		if err != nil {
			return nil, err
		}
		return &board_draw_api.UpdateEdgeBasicResponse{
			Code: board_draw_api.UpdateEdgeBasicResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.UpdateDrawNotice{
		BoardId: req.BoardId,
		DrawId:  req.DrawId,
	})
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.UpdateEdgeNotice{
		BoardId:    req.BoardId,
		DrawId:     req.DrawId,
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	return ret.(*board_draw_api.UpdateEdgeBasicResponse), nil
}

func (apiImpl *BoardDrawApiImpl) ListEdge(ctx context.Context, req *board_draw_api.ListEdgeRequest) (*board_draw_api.ListEdgeResponse, error) {
	emptyList := []*board_draw_api.DrawEdgeInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.ListEdgeResponse{
			Code:     board_draw_api.ListEdgeResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			EdgeList: emptyList,
		}, nil
	}
	//检查权限
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_draw_api.ListEdgeResponse{
			Code:     board_draw_api.ListEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			EdgeList: emptyList,
		}, nil
	}

	edgeItemList, err := board_dao.EdgeInfoDao.List(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return nil, err
	}
	//生成结果
	edgeList := []*board_draw_api.DrawEdgeInfo{}
	for _, edgeItem := range edgeItemList {
		edge := edgeItem.ToDrawEdgeInfo()
		edgeList = append(edgeList, edge)
	}
	return &board_draw_api.ListEdgeResponse{
		Code:     board_draw_api.ListEdgeResponse_CODE_OK,
		EdgeList: edgeList,
	}, nil
}

func (apiImpl *BoardDrawApiImpl) GetEdge(ctx context.Context, req *board_draw_api.GetEdgeRequest) (*board_draw_api.GetEdgeResponse, error) {
	emptyInfo := &board_draw_api.DrawEdgeInfo{}
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.GetEdgeResponse{
			Code:   board_draw_api.GetEdgeResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Edge:   emptyInfo,
		}, nil
	}
	//检查权限
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_draw_api.GetEdgeResponse{
			Code:   board_draw_api.GetEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Edge:   emptyInfo,
		}, nil
	}

	edgeItem, err := board_dao.EdgeInfoDao.Get(ctx, req.BoardId, req.DrawId, &board_dao.EdgeKeyDbItem{
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	if err != nil {
		return &board_draw_api.GetEdgeResponse{
			Code:   board_draw_api.GetEdgeResponse_CODE_NO_EDGE,
			ErrMsg: "连线不存在",
			Edge:   emptyInfo,
		}, nil
	}
	edge := edgeItem.ToDrawEdgeInfo()

	return &board_draw_api.GetEdgeResponse{
		Code: board_draw_api.GetEdgeResponse_CODE_OK,
		Edge: edge,
	}, nil
}

func (apiImpl *BoardDrawApiImpl) RemoveEdge(ctx context.Context, req *board_draw_api.RemoveEdgeRequest) (*board_draw_api.RemoveEdgeResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.RemoveEdgeResponse{
			Code:   board_draw_api.RemoveEdgeResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	edgeItem, err := board_dao.EdgeInfoDao.Get(ctx, req.BoardId, req.DrawId, &board_dao.EdgeKeyDbItem{
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	if err != nil {
		return &board_draw_api.RemoveEdgeResponse{
			Code: board_draw_api.RemoveEdgeResponse_CODE_OK,
		}, nil
	}

	if edgeItem.BasicInfo.LlmLink {
		return &board_draw_api.RemoveEdgeResponse{
			Code:   board_draw_api.RemoveEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	drawItem, err := board_dao.DrawInfoDao.Get(ctx, req.BoardId, req.DrawId)
	if err != nil {
		if err != nil {
			return &board_draw_api.RemoveEdgeResponse{
				Code:   board_draw_api.RemoveEdgeResponse_CODE_NO_DRAW,
				ErrMsg: "画稿不存在",
			}, nil
		}
	}

	//检查权限
	memberItem, err := board_dao.MemberInfoDao.Get(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return &board_draw_api.RemoveEdgeResponse{
			Code:   board_draw_api.RemoveEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(memberItem.Admin || drawItem.CanEdit(sessItem.UserId)) {
		return &board_draw_api.RemoveEdgeResponse{
			Code:   board_draw_api.RemoveEdgeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.EdgeInfoDao.Remove(sessCtx, req.BoardId, req.DrawId, &board_dao.EdgeKeyDbItem{
			FromNodeId: req.EdgeKey.FromNodeId,
			FromHandle: req.EdgeKey.FromHandle,
			ToNodeId:   req.EdgeKey.ToNodeId,
			ToHandle:   req.EdgeKey.ToHandle,
		})
		if err != nil {
			return nil, err
		}
		//更新连线数量
		count, err := board_dao.EdgeInfoDao.Count(sessCtx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		err = board_dao.DrawInfoDao.UpdateEdgeCount(sessCtx, req.BoardId, req.DrawId, count, nowTime)
		if err != nil {
			return nil, err
		}
		return &board_draw_api.RemoveEdgeResponse{
			Code: board_draw_api.RemoveEdgeResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.UpdateDrawNotice{
		BoardId: req.BoardId,
		DrawId:  req.DrawId,
	})
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.RemoveEdgeNotice{
		BoardId:    req.BoardId,
		DrawId:     req.DrawId,
		FromNodeId: req.EdgeKey.FromNodeId,
		FromHandle: req.EdgeKey.FromHandle,
		ToNodeId:   req.EdgeKey.ToNodeId,
		ToHandle:   req.EdgeKey.ToHandle,
	})
	return ret.(*board_draw_api.RemoveEdgeResponse), nil
}

func (apiImpl *BoardDrawApiImpl) RemoveEdgeByHandle(ctx context.Context, req *board_draw_api.RemoveEdgeByHandleRequest) (*board_draw_api.RemoveEdgeByHandleResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code:   board_draw_api.RemoveEdgeByHandleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	drawItem, err := board_dao.DrawInfoDao.Get(ctx, req.BoardId, req.DrawId)
	if err != nil {
		if err != nil {
			return &board_draw_api.RemoveEdgeByHandleResponse{
				Code:   board_draw_api.RemoveEdgeByHandleResponse_CODE_NO_DRAW,
				ErrMsg: "画稿不存在",
			}, nil
		}
	}
	//检查权限
	memberItem, err := board_dao.MemberInfoDao.Get(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code:   board_draw_api.RemoveEdgeByHandleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(memberItem.Admin || drawItem.CanEdit(sessItem.UserId)) {
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code:   board_draw_api.RemoveEdgeByHandleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//不能删除llm相关节点的边
	nodeItem, err := board_dao.NodeInfoDao.Get(ctx, req.BoardId, req.DrawId, req.NodeId)
	if err != nil { //节点不存在
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code: board_draw_api.RemoveEdgeByHandleResponse_CODE_OK,
		}, nil
	}
	node, err := nodeItem.ToDrawNodeInfo()
	if err != nil {
		return nil, err
	}
	llmAsk := &board_draw_type.LlmAskContent{}
	llmAnswer := &board_draw_type.LlmAnswerContent{}
	if node.Content.MessageIs(llmAsk) || node.Content.MessageIs(llmAnswer) {
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code:   board_draw_api.RemoveEdgeByHandleResponse_CODE_NO_PERMISSION,
			ErrMsg: "不能删除大模型节点相关连接",
		}, nil
	}

	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.EdgeInfoDao.RemoveByFromNodeHandle(sessCtx, req.BoardId, req.DrawId, req.NodeId, req.HandleList)
		if err != nil {
			return nil, err
		}
		err = board_dao.EdgeInfoDao.RemoveByToNodeHandle(sessCtx, req.BoardId, req.DrawId, req.NodeId, req.HandleList)
		if err != nil {
			return nil, err
		}
		//更新连线数量
		count, err := board_dao.EdgeInfoDao.Count(sessCtx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		err = board_dao.DrawInfoDao.UpdateEdgeCount(sessCtx, req.BoardId, req.DrawId, count, nowTime)
		if err != nil {
			return nil, err
		}
		return &board_draw_api.RemoveEdgeByHandleResponse{
			Code: board_draw_api.RemoveEdgeByHandleResponse_CODE_OK,
		}, nil
	})
	//发送通知
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.UpdateDrawNotice{
		BoardId: req.BoardId,
		DrawId:  req.DrawId,
	})
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.RemoveEdgeByHandleNotice{
		BoardId:    req.BoardId,
		DrawId:     req.DrawId,
		NodeId:     req.NodeId,
		HandleList: req.HandleList,
	})
	return ret.(*board_draw_api.RemoveEdgeByHandleResponse), nil
}
